package com.joysuch.wwyt.mh.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.common.enums.AppBusinessNoticeTypes;
import com.joysuch.wwyt.common.repository.CommonIndexNotifyDao;
import com.joysuch.wwyt.common.service.CommonIndexNotifyService;
import com.joysuch.wwyt.core.bean.SimpleSelectListBean;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiBusinessException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseRoleDataAuthService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.bean.MhMajorHazardPlanSearchBean;
import com.joysuch.wwyt.mh.bean.vo.MajorHazardPlanDeleteCheckVO;
import com.joysuch.wwyt.mh.bean.vo.MhMajorHazardPlanItemVO;
import com.joysuch.wwyt.mh.bean.vo.MhMajorHazardPlanPageVO;
import com.joysuch.wwyt.mh.bean.vo.MhMajorHazardPlanVO;
import com.joysuch.wwyt.mh.dto.MhMajorHazardPlanDTO;
import com.joysuch.wwyt.mh.dto.MhMajorHazardPlanItemDTO;
import com.joysuch.wwyt.mh.entity.*;
import com.joysuch.wwyt.mh.enums.MhMajorHazardCheckUserEnum;
import com.joysuch.wwyt.mh.enums.TaskStatus;
import com.joysuch.wwyt.mh.mapper.MhMajorHazardPlanItemMapper;
import com.joysuch.wwyt.mh.mapper.MhMajorHazardPlanMapper;
import com.joysuch.wwyt.mh.mapper.MhMajorHazardTaskAssignMapper;
import com.joysuch.wwyt.mh.mapper.MhMajorHazardTaskMapper;
import com.joysuch.wwyt.mh.repository.MhMajorHazardDao;
import com.joysuch.wwyt.mh.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zqw
 * @since 2022-05-17
 */
@Service
public class MhMajorHazardPlanServiceImpl extends ServiceImpl<MhMajorHazardPlanMapper, MhMajorHazardPlan> implements MhMajorHazardPlanService {

    @Autowired
    private MhMajorHazardPlanMapper mhMajorHazardPlanMapper;
    @Autowired
    private MhMajorHazardPlanItemService mhMajorHazardPlanItemService;
    @Autowired
    private MhMajorHazardDao mhMajorHazardDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BaseRoleDataAuthService baseRoleDataAuthService;
    @Autowired
    private MhMajorHazardTaskService mhMajorHazardTaskService;
    @Autowired
    private MhMajorHazardPlanItemMapper mhMajorHazardPlanItemMapper;
    @Autowired
    private MhMajorHazardTaskMapper mhMajorHazardTaskMapper;
    @Autowired
    private MhMajorHazardTaskAssignMapper mhMajorHazardTaskAssignMapper;
    @Autowired
    private CommonIndexNotifyService indexNotifyService;
    @Autowired
    private CommonIndexNotifyDao commonIndexNotifyDao;
    @Autowired
    private MhMajorHazardTaskRecordService mhMajorHazardTaskRecordService;
    @Autowired
    private MhMajorHazardTaskAssignService mhMajorHazardTaskAssignService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MhMajorHazardPlan savePlan(MhMajorHazardPlanDTO dto) {
        boolean isNew = true;
        MhMajorHazardPlan plan = new MhMajorHazardPlan();
        if (dto.getId() != null) {
            plan = getById(dto.getId());
            if (plan == null) {
                throw new IllegalArgumentException("该计划不存在");
            }
            if (!plan.getCycleType().equals(dto.getCycleType())) {
                throw new IllegalArgumentException("请勿更改该计划的周期类型");
            }
            isNew = false;
        }
        int count = mhMajorHazardPlanMapper.countByPlanNameAndId(dto.getPlanName(), dto.getId(), Context.getCompanyCode(), Context.getCurrentTenantId());
        if (count > 0) {
            throw new IllegalArgumentException("计划名称已存在");
        }
        //组装plan数据
        plan = convertPlan(dto, plan);
        saveOrUpdate(plan);
        //删除,保存指标
        handleItems(plan.getId(), dto.getDeleteItemIds(), dto.getItemBeanList());
        //生成任务
        mhMajorHazardTaskService.produceTaskByPlan(plan, isNew);
        return plan;
    }

    private MhMajorHazardPlan convertPlan(MhMajorHazardPlanDTO dto, MhMajorHazardPlan plan) {
        BeanUtils.copyProperties(dto, plan);
        String cycleData = null;
        if (!CollectionUtils.isEmpty(dto.getCycleData())) {
            cycleData = JSONUtil.toJsonPrettyStr(dto.getCycleData());
        }
        plan.setCycleData(cycleData);
        //检查人 0主要负责人,1技术负责人,2操作负责人
        String checkUserIds = null;
        MhMajorHazard mh = mhMajorHazardDao.findByIdAndEfficient(dto.getMajorHazardId()).orElseThrow(() -> new IllegalArgumentException("危险源不存在或被删除,请重新设置危险源"));
        if (dto.getCheckUserType().equals(MhMajorHazardCheckUserEnum.RESPONSIBLE_USER.getCode())) {
            checkUserIds = mh.getResponsibleUserId();
        } else if (dto.getCheckUserType().equals(MhMajorHazardCheckUserEnum.TECHNOLOGY_USER.getCode())) {
            checkUserIds = mh.getTechnologyUserId();
        } else if (dto.getCheckUserType().equals(MhMajorHazardCheckUserEnum.OPERATION_USER.getCode())) {
            checkUserIds = mh.getOperationUserId();
        }
        if (StringUtils.isBlank(checkUserIds)) {
            throw new IllegalArgumentException("检查人员不能为空,请设置重大危险源[" + mh.getName() + "]的" + MhMajorHazardCheckUserEnum.getNameByCode(dto.getCheckUserType()));
        }
        plan.setCheckUserIds(checkUserIds);
        //随行人
        String entourageIds = null;
        if (!CollectionUtils.isEmpty(dto.getEntourageIds())) {
            entourageIds = dto.getEntourageIds().stream().map(Object::toString).collect(Collectors.joining(Constant.SPLIT_COMMA));
        }
        plan.setEntourageIds(entourageIds);
        //任务时间
        plan.setTaskTimeDesc(getPagePlanTaskTime(plan));
        return plan;
    }

    @Override
    public ResultBean pagePlan(MhMajorHazardPlanSearchBean searchBean) {
        List<MhMajorHazardPlanPageVO> voList = new ArrayList<>();
        //只有拥有制定部门权限的数据才能被查看
        List<Long> authDepartIds = baseRoleDataAuthService.findDepartIdsByCurUser();
        if (CollectionUtils.isEmpty(authDepartIds)) {
            return ResultBean.pageData(voList, 0);
        }
        List<Long> checkUserIds = new ArrayList<>();
        Page<MhMajorHazardPlan> page = new Page<>(searchBean.getPage() + 1, searchBean.getSize());
        if (StringUtils.isNotBlank(searchBean.getCheckUserName())) {
            checkUserIds = baseUserDao.findIdsByRealName(searchBean.getCheckUserName());
            if (CollectionUtils.isEmpty(checkUserIds)) {
                return ResultBean.pageData(voList, 0);
            }
        }
        Page<MhMajorHazardPlan> pageData = mhMajorHazardPlanMapper.selectByPage(page, checkUserIds, authDepartIds, searchBean.getCycleType(), searchBean.getPlanName(), Context.getCompanyCode(), Context.getCurrentTenantId(), searchBean.getMajorHazardId());
        List<MhMajorHazardPlan> plans = pageData.getRecords();
        Map<Long, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(plans)) {
            List<Long> majorHazardIds = plans.stream().map(MhMajorHazardPlan::getMajorHazardId).collect(Collectors.toList());
            List<MhMajorHazard> majorHazards = mhMajorHazardDao.findByIds(majorHazardIds);
            map = majorHazards.stream().collect(Collectors.toMap(MhMajorHazard::getId, MhMajorHazard::getName));
        }
        for (MhMajorHazardPlan plan : pageData.getRecords()) {
            MhMajorHazardPlanPageVO vo = new MhMajorHazardPlanPageVO();
            BeanUtils.copyProperties(plan, vo);
            //检查人
            vo.setCheckUserName(getPagePlanCheckUserName(plan));
            vo.setMajorHazardName(map.get(plan.getMajorHazardId()));
            //todo 检查对象查阅状态
            voList.add(vo);
        }
        return ResultBean.pageData(voList, page.getTotal());
    }

    //计划分页任务时间
    private String getPagePlanTaskTime(MhMajorHazardPlan plan) {
        String taskTime = null;
        //0周检查 1季度检查 2-月度检查3-半年度检查
        Integer cycleType = plan.getCycleType();
        //0周期内循环,1单次
        Integer loopType = plan.getLoopType();
        //周期数据年:季度单次，周循环 单词确定哪一年
        Integer cycleYear = plan.getCycleYear();
        //周期数据月:周单次确定哪一月
        Integer cycleMonth = plan.getCycleMonth();
        //周单次->存本年选中的周 ;周循环->存本年月份集合;季度单次->存选中的季度;季度循环->存选中年分集合
        String cycleData = plan.getCycleData();
        if (cycleType == null || loopType == null || StringUtils.isBlank(cycleData)) {
            return taskTime;
        }
        List<Integer> dataList = JSONUtil.toList(cycleData, Integer.class);
        String dataStr = dataList.stream().map(String::valueOf).collect(Collectors.joining(Constant.SPLIT_COMMA));
        if (cycleType.equals(0)) {
            if (cycleYear == null) {
                return taskTime;
            }
            if (loopType == 0) {
                taskTime = cycleYear + "年" + dataStr + "月";
            } else if (loopType == 1) {
                if (cycleMonth == null) {
                    return taskTime;
                }
                taskTime = cycleYear + "年" + cycleMonth + "月第" + dataList.get(0) + "周";
            }
        } else if (cycleType == 1) {
            if (loopType == 0) {
                taskTime = dataStr + "年";
            } else if (loopType == 1) {
                if (cycleYear == null) {
                    return taskTime;
                }
                taskTime = cycleYear + "年第" + dataList.get(0) + "季度";
            }
        } else if (cycleType == 2) {  // 月度检查
            if (loopType == 0) {
                taskTime = dataStr + "年";
            } else if (loopType == 1) {
                if (cycleYear == null && dataList.get(0) == null) {
                    return taskTime;
                }
                taskTime = cycleYear + "年第" + dataList.get(0) + "月";
            }
        } else if (cycleType == 3) {  // 半年度
            if (loopType == 0) {
                taskTime = dataStr + "年";
            } else if (loopType == 1) {
                if (cycleYear == null && dataList.get(0) != 1 && dataList.get(0) != 2) {
                    return taskTime;
                }
                String period = dataList.get(0) == 1 ? "上半年" : "下半年";
                taskTime = cycleYear + "年" + period;
            }
        }
        return taskTime;
    }

    //计划分页检查人
    @Override
    public String getPagePlanCheckUserName(MhMajorHazardPlan plan) {
        String checkUserName = null;
        if (StringUtils.isNotBlank(plan.getCheckUserIds())) {
            List<Long> userIds = Arrays.asList(plan.getCheckUserIds().split(",")).stream().map(s -> Long.valueOf(s)).collect(Collectors.toList());
            List<BaseUser> users = baseUserDao.getAllByIds(userIds);
            String checkUserType = MhMajorHazardCheckUserEnum.getNameByCode(plan.getCheckUserType());
            if (StringUtils.isNotBlank(checkUserType) && !CollectionUtils.isEmpty(users)) {
                String userNameStr = users.stream().map(BaseUser::getRealName).collect(Collectors.joining(Constant.SPLIT_COMMA));
                checkUserName = userNameStr + "(" + checkUserType + ")";
            }
        }
        return checkUserName;
    }

    @Override
    public MhMajorHazardPlanVO findById(Long id) {
        MhMajorHazardPlanVO vo = new MhMajorHazardPlanVO();
        MhMajorHazardPlan plan = getById(id);
        if (plan == null) {
            throw new IllegalArgumentException("计划不存在");
        }
        BeanUtils.copyProperties(plan, vo);
        MhMajorHazard mhMajorHazard = mhMajorHazardDao.findById(plan.getMajorHazardId()).orElseThrow(() -> new IllegalArgumentException("危险源不存在"));
        vo.setMajorHazardName(mhMajorHazard.getName());
        //周期数据
        if (StringUtils.isNotBlank(plan.getCycleData())) {
            vo.setCycleData(JSONUtil.toList(plan.getCycleData(), Integer.class));
        }
        //随行人
        if (StringUtils.isNotBlank(plan.getEntourageIds())) {
            List<SimpleSelectListBean> entourageIds = new ArrayList<>();
            List<Long> userIds = Arrays.asList(plan.getEntourageIds().split(",")).stream().map(s -> Long.valueOf(s)).collect(Collectors.toList());
            List<BaseUser> users = baseUserDao.getAllByIds(userIds);
            if (!CollectionUtils.isEmpty(users)) {
                users.forEach(user -> {
                    SimpleSelectListBean bean = new SimpleSelectListBean();
                    bean.setLabel(user.getRealName());
                    bean.setValue(user.getId());
                    entourageIds.add(bean);
                });
                vo.setEntourageIds(entourageIds);
            }
        }
        //制定人
        Optional<BaseUser> obu = baseUserDao.findById(plan.getFormulateUserId());
        if (obu.isPresent()) {
            vo.setFormulateUserName(obu.get().getRealName());
        }
        //制定部门
        Optional<BpDepart> obd = bpDepartDao.findById(plan.getFormulateDepartId());
        if (obd.isPresent()) {
            vo.setFormulateDepartName(obd.get().getName());
        }
        List<MhMajorHazardPlanItemVO> itemVos = mhMajorHazardPlanItemService.findByPlanId(plan.getId(), DeleteFlag.EFFECTIVE.getCode());
        vo.setItemVos(itemVos);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) throws ApiBusinessException {
        MhMajorHazardPlan plan = getById(id);
        if (plan != null) {
            MajorHazardPlanDeleteCheckVO vo = new MajorHazardPlanDeleteCheckVO();
            // 任务列表
            List<MhMajorHazardTask> list = mhMajorHazardTaskService.list(new QueryWrapper<MhMajorHazardTask>()
                    .eq("plan_id", id)
                    .eq("delete_flag", "0"));
            vo.setTaskName(plan.getPlanName());
            if (!CollectionUtils.isEmpty(list)) {
                List<Long> taskIds = list.stream().map(MhMajorHazardTask::getId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(taskIds)) {
                    int taskAssignNum = mhMajorHazardTaskAssignService.count(new QueryWrapper<MhMajorHazardTaskAssign>()
                            .eq("delete_flag", "0")
                            .eq("done_status", 0)
                            .in("task_id", taskIds));
                    vo.setTaskNum(taskAssignNum);
                    int recordCount = mhMajorHazardTaskRecordService.count(new QueryWrapper<MhMajorHazardTaskRecord>()
                            .eq("delete_flag", "0")
                            .in("task_id", taskIds));
                    vo.setRecordNum(recordCount);
                }
            }
            if (vo.getTaskNum() + vo.getRecordNum() > 0) {
                throw new ApiBusinessException(Status.DELETE_CHECK_FAILED.getCode(), JSONObject.toJSONString(vo));
            }

            plan.setDeleteFlag(DeleteFlag.DELETED.getCode());
            saveOrUpdate(plan);
            List<MhMajorHazardPlanItem> itemList = mhMajorHazardPlanItemMapper.findByPlanId(id, DeleteFlag.EFFECTIVE.getCode());
            if (!CollectionUtils.isEmpty(itemList)) {
                itemList.forEach(item -> {
                    item.setDeleteFlag(DeleteFlag.DELETED.getCode());
                });
                mhMajorHazardPlanItemService.saveOrUpdateBatch(itemList);
            }

            //删除未推送的消息
            List<MhMajorHazardTask> taskList = mhMajorHazardTaskMapper.findUnFinishedTasksByPlanId(id);
            if (!CollectionUtils.isEmpty(taskList)) {
                List<Long> taskIds = taskList.stream().map(MhMajorHazardTask::getId).collect(Collectors.toList());
                List<MhMajorHazardTaskAssign> assignList = mhMajorHazardTaskAssignMapper.findByTaskIds(taskIds, TaskStatus.UNFINISH.getStatus());
                if (!CollectionUtils.isEmpty(assignList)) {
                    List<Long> assignIdList = assignList.stream().map(MhMajorHazardTaskAssign::getId).collect(Collectors.toList());
                    commonIndexNotifyDao.deletePlanByTaskIds(assignIdList, AppBusinessNoticeTypes.EMERGENCY_DRILL_PLAN.getType());
                }

            }


            //删除未做的任务
            mhMajorHazardTaskService.deleteUnFinishedTask(plan.getId());


        }
    }

    private List<MhMajorHazardPlanItem> handleItems(Long planId, List<Long> deleteItemIds, List<MhMajorHazardPlanItemDTO> itemDtoList) {
        //删除检查项
        mhMajorHazardPlanItemService.deleteByIds(deleteItemIds);
        //保存检查项
        List<MhMajorHazardPlanItem> items = mhMajorHazardPlanItemService.saveItems(planId, itemDtoList);
        return items;
    }

}
